package view;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JInternalFrame;

import controller.Controller;

import util.Coord;

public class WorldView extends GamePanel implements KeyListener, MouseListener{
	private static final long serialVersionUID = 1L;
	private int dx, dy; 	//Scroll speed
	private static final int TILE_WIDTH = 100;
	private static final int TILE_HEIGHT = 86;
	private long vx, vy;
	CraftingFrame craftingFrame;

	public WorldView(Stage parent, Controller controller, int w, int h){
		super(parent, controller, w, h);
		this.addKeyListener(this);
		this.addMouseListener(this);
	}

	protected void init() {
		setFocusable(true);
		dx = dy = 0;
		vx = vy = 0;
		centerOnWorld(0,0);
		setBackground(Color.black);
		setLayout(null);
		
		craftingFrame = new CraftingFrame(parent, controller);
		craftingFrame.setSize(this.WIDTH*3/5, this.HEIGHT*4/5);
		craftingFrame.setVisible(false);
		add(craftingFrame);
		
		repaint();
	}

	@Override
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		Coord NW = getNWWorldCoord();
		Coord SE = getSEWorldCoord();
		long x = NW.getX() - 1;
		long y = NW.getY();
		long py = y;
		int changeY = 0;

		while(x != SE.getX() || y != SE.getY()){
			if(x == SE.getX()){
				x = NW.getX();
				py++;
				y = py;
				changeY = 0;
			}else{
				x++;
			}
			if(changeY == 0){
				changeY = -1;
			}else{
				y--;
			}
			Coord loc = new Coord(worldToView(x, y));
			drawTile(g, x, y, (int)(loc.getX() - vx), (int)(loc.getY() - vy));
			drawEntity(g, x, y, (int)(loc.getX() - vx), (int)(loc.getY() - vy));
		}
		Font font = new Font("Times New Roman", Font.BOLD, 24);
		g.setFont(font);
		g.setColor(Color.black);
		g.drawString("x: " + viewToWorld(vx, vy).getX() + "      vx:" + vx, 10, 20);
		g.drawString("y: " + viewToWorld(vx, vy).getY() + "      vy:" + vy, 10, 40);
	}
	
	private void centerOnWorld(long wx, long wy){
		vx = worldToView(wx, wy).getX() - this.getWidth()/2 + TILE_WIDTH/2;
		vy = worldToView(wx, wy).getY() - this.getHeight()/2 + TILE_HEIGHT/2;
	}

	private void drawEntity(Graphics g, long wx, long wy, int vx, int vy) {
		int id = mr.getEntityID(wx, wy);
		String path = null;
		switch(id){
		case 1:
			path = "/resource/Player.png";
			break;
		case 100:
			path = "/resource/Tipi.png";
			break;
		default: 
			break;
		}
		if(path != null) {
			drawImage(g, path, vx, vy);
		}
	}

	private Coord worldToView(long wx, long wy){
		long vx = (long) (wx*(TILE_WIDTH - TILE_HEIGHT*Math.tan(Math.toRadians(30))/2));
		long vy = (long) (TILE_HEIGHT*(wx/2.0 + wy));
		return new Coord(vx, vy);
	}

	private Coord viewToWorld(long vx, long vy){
		Coord estimate = new Coord();
		estimate.setX((long) (vx/(TILE_WIDTH - TILE_HEIGHT*Math.tan(Math.toRadians(30))/2)));
		estimate.setY(vy/TILE_HEIGHT - estimate.getX()/2);

		long distanceToPoint = TILE_WIDTH*TILE_HEIGHT;

		Coord best = new Coord();

		for(long y = estimate.getY()-1; y <= estimate.getY()+1; y++){
			for(long x = estimate.getX()-1; x <= estimate.getX()+1; x++){
				long distance = (long) Math.sqrt((vx - (worldToView(x, y).getX() + TILE_WIDTH/2))*(vx - (worldToView(x, y).getX() + TILE_WIDTH/2)) + (vy - (worldToView(x, y).getY() + TILE_HEIGHT/2))*(vy - (worldToView(x, y).getY() + TILE_HEIGHT/2)));
				if(distance <= distanceToPoint){
					best.setX(x);
					best.setY(y);
					distanceToPoint = distance;
				}
			}
		}

		return best;
	}

	private void drawTile(Graphics g, long wx, long wy, int vx, int vy) {
		int id = mr.getTileType(wx, wy);
		String path = null;
		switch(id){
		case 0:
			path = "/resource/Tiles/Bog.png";
			break;
		case 1:
			path = "/resource/Tiles/Wood.png";
			break;
		case 2:
			path = "/resource/Tiles/Stone.png";
			break;
		case 3:
			path = "/resource/Tiles/Field.png";
			break;
		default: 
			break;
		}
		if(path != null) {
			drawImage(g, path, vx, vy);
		}
	}

	private void drawImage(Graphics g, String path, int vx, int vy) {
		ImageIcon icon = new ImageIcon(getClass().getResource(path));
		g.drawImage(icon.getImage(), vx, vy, null);
	}

	private Coord getNWWorldCoord(){
		Coord nw = viewToWorld(vx, vy);
		nw.setX(nw.getX() - 1);
		return nw;
	}

	private Coord getSEWorldCoord(){
		Coord se = viewToWorld(vx + getWidth(), vy + getHeight());
		se.setX(se.getX() + 1);
		se.setY(se.getY() + 1);
		return se;
	}

	@Override
	public void keyPressed(KeyEvent e) {
		switch(e.getKeyCode()){
		case KeyEvent.VK_UP:
			dy = -10;
			break;
		case KeyEvent.VK_DOWN:
			dy = 10;
			break;
		case KeyEvent.VK_RIGHT:
			dx = 10;
			break;
		case KeyEvent.VK_LEFT:
			dx = -10;
			break;
		default:
			break;
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
		int kc = e.getKeyCode();
		if(kc == KeyEvent.VK_UP || kc == KeyEvent.VK_DOWN){
			dy = 0;
		}
		if(kc == KeyEvent.VK_LEFT || kc == KeyEvent.VK_RIGHT){
			dx = 0;
		}
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@SuppressWarnings("unused")
	@Override
	protected void update() {
		requestFocus();
		if(!controller.isCraftingOpen()){
			craftingFrame.setVisible(false);
			vx += dx;
			vy += dy;
			repaint();
		}else{
			craftingFrame.setVisible(true);
			craftingFrame.update();
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		Coord wc = new Coord(viewToWorld(e.getX() + vx, e.getY() + vy));
		switch(e.getButton()){
		case MouseEvent.BUTTON1:
			controller.leftClickTile(wc.getX(), wc.getY());
			break;
		case MouseEvent.BUTTON3:
			controller.rightClickTile(wc.getX(), wc.getY());
			break;
		}
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	public Coord getMapCenter() {
		return viewToWorld(vx + this.WIDTH/2, vy + this.HEIGHT/2);
	}
}
